package t10086.Controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;
import t10086.Configure.InitConfig;
import t10086.Configure.SocketConfig;
import t10086.Data.Map.GridType;
import t10086.Data.Map.T10086Map;
import t10086.Data.Map.TextCoordinate;
import t10086.Data.Robot.InitRobot;
import t10086.WorkThread.Shared.ClientMap;
import t10086.WorkThread.Shared.DataBuffer;
import t10086.Model.Entity.Order;
import t10086.Model.Entity.Robot;
import t10086.Model.Http.Response;
import t10086.Service.OrderService;
import t10086.Service.RobotService;
import t10086.Tookit.StrUtil;
import t10086.WorkThread.MsgProcessHandler;
import t10086.WorkThread.SocketServer;
import t10086.WorkThread.ThreadPoolManager;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@RestController
@RequestMapping("cmd")
public class CommanderController {
    private final ResourceLoader resourceLoader;
    private final RobotService robotService;
    private final OrderService orderService;
    public static int started = 0;
    private final SocketConfig socketConfig;
    private ServerSocket serverSocket;
    private final WebClient.Builder webClientBuilder;
    private static final int robotToGrid = (int) 1.3f;//格子比机器人大小系数，整数倍切割
    private long startTime;

    @Autowired
    public CommanderController(ResourceLoader resourceLoader, RobotService robotService,
                               OrderService orderService, SocketConfig socketConfig,
                               WebClient.Builder webClientBuilder) {
        this.resourceLoader = resourceLoader;
        this.robotService = robotService;
        this.orderService = orderService;
        this.socketConfig = socketConfig;
        this.webClientBuilder = webClientBuilder;
    }

    @GetMapping("/start")
    public Response start(@RequestParam(required = false, name = "robotCount") Integer robotCount) {
        Response response = new Response();
        if (started != 0) {
            response.setMessage("system already started!");
            response.setStatusCode(202);
        } else if (robotCount == null) {
            response.setMessage("please input robotCount!");
            response.setStatusCode(202);
        } else if (robotCount <= 0) {
            response.setMessage("please input robotCount greater than 0!");
            response.setStatusCode(202);
        } else {
            started = 1;
            try {
                this.serverSocket = new ServerSocket(socketConfig.getPort(), socketConfig.getMaxBacklog(),
                        socketConfig.getAddress());
                System.out.println("Socket server started on port " + socketConfig.getPort());
                ThreadPoolManager.submitTask(new SocketServer(serverSocket));//启动socket服务器
                ThreadPoolManager.submitTask(new MsgProcessHandler());//启动外部信息处理线程
                response.setMessage("commander started!");
            } catch (IOException e) {
                started = 0;
                System.out.println("Socket server started failed!");
                response.setStatusCode(202);
                response.setMessage("Socket server started failed!");
                return response;
            }
            if (!init(robotCount)) {
                response.setStatusCode(202);
                response.setMessage("Robot Initial failed!");
                started = 0;
                return response;
            }
            started = 2;
            this.startTime = Instant.now().getEpochSecond();
        }
        return response;
    }

    @GetMapping("/aliveTime")
    public Response aliveTime() {
        Response response = new Response();
        if (started == 0)
            response.addData("aliveTime", 0);
        else
            response.addData("aliveTime", Instant.now().getEpochSecond() - startTime);
        return response;
    }

    @GetMapping("/stop")
    public Response stop() {
        Response response = new Response();
        if (started == 2) {
            synchronized (DataBuffer.class) {
                DataBuffer.clear();//管理内容清除
            }
            try {
                serverSocket.close();//关闭服务器
            } catch (IOException e) {
                System.out.println("Socket server stop failed!");
            }
            ThreadPoolManager.terminateAllTasks();//清除连接关联线程。
            ClientMap.removeAllClients();//清除所有连接
            started = 0;
            response.setMessage("stopped successfully!");
        } else if (started == 1) {
            response.setMessage("Please wait stating!");
        } else
            response.setMessage("system already stopped!");
        return response;
    }

    public boolean init(int robotCount) {
       // initOrder(1000);//初始化订单
        boolean flag1 = initMap();//初始化地图
        boolean flag2 = initRobot(robotCount);//初始化机器人
        return flag1 && flag2;
    }

    public boolean initRobot(int robotCount) {
        List<Robot> robots = robotService.getRobotsPaged(0, robotCount);
        List<InitRobot> initRobots = new ArrayList<InitRobot>();
        int x = 0, y = robotToGrid * 49;
        for (Robot robot : robots) {
            initRobots.add(new InitRobot(robot.getSerialNumber(), new TextCoordinate(x, y)));
            y -= 1;
        }

        List<String> urls = InitConfig.robotInitConfigs;
        int clientNum = urls.size();
        int part = robotCount / clientNum;
        int end = 0;

        for (int i=0;i<clientNum;i++) {
            WebClient webClient = webClientBuilder.baseUrl("http://" + urls.get(i) + "/systemapi/getrobotlist").build();
            Map<String, List<InitRobot>> data = new HashMap<>();
            if(i!=clientNum-1)
                data.put("robotList", new ArrayList<>(initRobots.subList(end, end+part)));
            else
                data.put("robotList", new ArrayList<>(initRobots.subList(end, robotCount)));
            // 执行 WebClient 请求并不等待响应
            webClient.post()
                    .bodyValue(data)
                    .retrieve()
                    .bodyToMono(Response.class)
                    .doOnTerminate(() -> System.out.println("Request completed"))
                    .subscribe();// 请求完成时执行的逻辑
            end+=part;
        }
        return true;
    }

    public void initOrder(int orderCount) {
        StrUtil strUtil = new StrUtil();
        int orderStart = 10000;
        int patientStart = 10000;
        int doctorStart = 10000;
        String orderHeader = "od";
        String patientHeader = "pat";
        String doctorHeader = "dc";
        for (int i = 0; i < orderCount; i++) {
            orderService.saveOrder(new Order(
                    orderHeader + (orderStart + i),
                    strUtil.generateName(),
                    patientHeader + (patientStart + i),
                    strUtil.generateName(),
                    doctorHeader + (doctorStart + i),
                    ""
            ));
        }
    }

    public boolean initMap() {

        Resource mapResource = resourceLoader.getResource("classpath:map.txt");
        String mapRegex = "\\((\\d+),\\s*(\\d+)\\),\\s*(\\w+)";
        Pattern mapPattern = Pattern.compile(mapRegex);
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(mapResource.getInputStream()))) {
            String line;
            T10086Map map = new T10086Map(50 * robotToGrid, 50 * robotToGrid);
            while ((line = reader.readLine()) != null) {
                // 创建匹配器
                Matcher matcher = mapPattern.matcher(line);
                if (matcher.find()) {
                    int x = Integer.parseInt(matcher.group(2));//地图编辑器是反着的
                    int y = Integer.parseInt(matcher.group(1));

                    switch (matcher.group(3)) {
                        case "blue" -> {
                            for (int i = x * robotToGrid; i < (x + 1) * robotToGrid; i++) {
                                for (int j = y * robotToGrid; j < (y + 1) * robotToGrid; j++) {
                                    map.getGrid(x, y).setGridType(GridType.BARRIER);

                                }
                            }
                        }
                        case "green" -> {
                            for (int i = x * robotToGrid; i < (x + 1) * robotToGrid; i++) {
                                for (int j = y * robotToGrid; j < (y + 1) * robotToGrid; j++) {
                                    map.getGrid(x, y).setGridType(GridType.PHARMACIST);
                                    map.getGrid(x, y).setRobotSerialNumber("DELIVER");
                                }
                            }
                        }
                        case "yellow" -> {
                            for (int i = x * robotToGrid; i < (x + 1) * robotToGrid; i++) {
                                for (int j = y * robotToGrid; j < (y + 1) * robotToGrid; j++) {
                                    map.getGrid(x, y).setGridType(GridType.DELIVER);
                                    map.getGrid(x, y).setRobotSerialNumber("PH1");
                                }
                            }
                        }
                        default -> {
                        }
                    }
                }
            }
            DataBuffer.getBroadcast().setMap(map);
        } catch (IOException e) {
            System.out.println("MAP INIT ERROR");
            return false;
        }

        Resource windowResource = resourceLoader.getResource("classpath:window.txt");
        String windowRegex = "(\\w+):\\((\\d+),\\s*(\\d+)\\)";
        Pattern windowPattern = Pattern.compile(windowRegex);
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(windowResource.getInputStream()))) {
            String line;
            int windowNum = 0;
            while ((line = reader.readLine()) != null) {
                Matcher matcher = windowPattern.matcher(line);
                if (matcher.find()) {
                    int x = Integer.parseInt(matcher.group(3));
                    int y = Integer.parseInt(matcher.group(2));
                    switch (matcher.group(1)) {
                        case "window" -> {
                            TextCoordinate textCoordinate = new TextCoordinate(x * robotToGrid, (y + 1) * robotToGrid);
                            DataBuffer.getBroadcast().addWindow(windowNum, textCoordinate);
                            DataBuffer.getBroadcast().addWindowQueue(windowNum, new HashMap<>());
                            windowNum++;
                        }
                        case "deliver" -> {
                            TextCoordinate textCoordinate = new TextCoordinate(x * robotToGrid, y * robotToGrid - 1);
                            DataBuffer.getBroadcast().setDeliverCoordinate(textCoordinate);
                            DataBuffer.getBroadcast().getMap().getGrid(x, y).setGridType(GridType.DELIVER);
                        }
                    }
                }
            }
        } catch (IOException e) {
            System.out.println("WINDOW INIT ERROR");
            return false;
        }

        return true;
    }


}
